﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Reflection;
using System.Collections;

namespace He.Common
{
    public class ESBasic
    {
        #region ESBasic
        public static string XmlSerializeObject(object target)
        {
            string typeName = GetClassSimpleName(target.GetType());
            XmlDocument xmlDoc = new XmlDocument();
            XmlElement objNode = xmlDoc.CreateElement(typeName);

            foreach (PropertyInfo pro in target.GetType().GetProperties())
            {
                if ((!pro.CanRead))
                {
                    continue;
                }
                if (pro.GetValue(target, null) != null)
                {
                    DoXmlSerializeObject(objNode, pro, pro.GetValue(target, null));
                }
            }

            return objNode.OuterXml;
        }

        /// <summary>
        /// GetClassSimpleName 获取class的声明名称，如 Person
        /// </summary>      
        public static string GetClassSimpleName(Type t)
        {
            string[] parts = t.ToString().Split('.');
            return parts[parts.Length - 1].ToString();
        }
        private static void DoXmlSerializeObject(XmlNode curNode, PropertyInfo pro, object val)
        {
            bool isGenericList = pro.PropertyType.IsGenericType && (pro.PropertyType.GetGenericTypeDefinition() == typeof(IList<>));
            if (isGenericList)
            {
                string listName = pro.Name;
                XmlNode listNode = curNode.OwnerDocument.CreateElement(listName);
                curNode.AppendChild(listNode);

                Type listElementType = pro.PropertyType.GetGenericArguments()[0];
                if (IsSimpleType(listElementType))
                {
                    foreach (object element in (IEnumerable)val)
                    {
                        SetPropertyValue(listNode, "value", element.ToString(), XmlPropertyPosition.ChildNode, false);
                    }
                }
                else
                {
                    foreach (object element in (IEnumerable)val)
                    {
                        string newObjName = GetClassSimpleName(listElementType);
                        XmlNode newObjNode = curNode.OwnerDocument.CreateElement(newObjName);
                        listNode.AppendChild(newObjNode);

                        PropertyInfo[] childPros = listElementType.GetProperties();
                        foreach (PropertyInfo childPro in childPros)
                        {
                            if ((!childPro.CanRead))
                            {
                                continue;
                            }

                            object childVal = childPro.GetValue(element, null);
                            DoXmlSerializeObject(newObjNode, childPro, childVal);
                        }
                    }
                }
            }
            else if (IsSimpleType(pro.PropertyType))
            {
                string valStr = (val == null ? "" : val.ToString());
                SetPropertyValue(curNode, pro.Name, valStr);
            }
            else
            {
                string newObjName = GetClassSimpleName(pro.PropertyType);
                XmlNode newObjNode = curNode.OwnerDocument.CreateElement(newObjName);
                curNode.AppendChild(newObjNode);

                PropertyInfo[] childPros = pro.PropertyType.GetProperties();
                foreach (PropertyInfo childPro in childPros)
                {
                    if ((!childPro.CanRead))
                    {
                        continue;
                    }

                    DoXmlSerializeObject(newObjNode, childPro, childPro.GetValue(val, null));
                }
            }

        }

        /// <summary>
        /// IsSimpleType 是否为简单类型：数值、字符、字符串、日期、布尔、枚举、Type
        /// </summary>      
        public static bool IsSimpleType(Type t)
        {
            if (IsNumbericType(t))
            {
                return true;
            }

            if (t == typeof(char))
            {
                return true;
            }

            if (t == typeof(string))
            {
                return true;
            }


            if (t == typeof(bool))
            {
                return true;
            }


            if (t == typeof(DateTime))
            {
                return true;
            }

            if (t == typeof(Type))
            {
                return true;
            }

            if (t.IsEnum)
            {
                return true;
            }

            return false;
        }

        public static bool IsNumbericType(Type destDataType)
        {
            if ((destDataType == typeof(int)) || (destDataType == typeof(uint)) || (destDataType == typeof(double))
                || (destDataType == typeof(short)) || (destDataType == typeof(ushort)) || (destDataType == typeof(decimal))
                || (destDataType == typeof(long)) || (destDataType == typeof(ulong)) || (destDataType == typeof(float))
                || (destDataType == typeof(byte)) || (destDataType == typeof(sbyte)))
            {
                return true;
            }

            return false;
        }

        public static void SetPropertyValue(XmlNode objNode, string proName, string val)
        {
            SetPropertyValue(objNode, proName, val, XmlPropertyPosition.ChildNode);
        }

        public static void SetPropertyValue(XmlNode objNode, string proName, string val, XmlPropertyPosition pos)
        {
            SetPropertyValue(objNode, proName, val, pos, true);
        }

        public static void SetPropertyValue(XmlNode objNode, string proName, string val, XmlPropertyPosition pos, bool overrideExist)
        {
            if (pos == XmlPropertyPosition.ChildNode)
            {
                if (overrideExist)
                {
                    foreach (XmlNode childNode in objNode.ChildNodes)
                    {
                        if (childNode.Name == proName)
                        {
                            childNode.InnerText = val;
                            return;
                        }
                    }
                }

                XmlNode newChildNode = objNode.OwnerDocument.CreateElement(proName);
                newChildNode.InnerText = val;
                objNode.AppendChild(newChildNode);
            }
            else
            {
                if (overrideExist)
                {
                    foreach (XmlAttribute attr in objNode.Attributes)
                    {
                        if (attr.Name == proName)
                        {
                            attr.Value = val;
                            return;
                        }
                    }
                }

                XmlAttribute newAttr = objNode.OwnerDocument.CreateAttribute(proName);
                objNode.Attributes.Append(newAttr);
                newAttr.Value = val;
            }
        }

        public enum XmlPropertyPosition
        {
            Attribute,
            ChildNode
        }
        #endregion
    }
}
